﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Goldlight.Mvvm.Base.Infrastructure;
using System.Transactions;
using System.IO;
using Microsoft.Win32.SafeHandles;
using System.Security;

namespace Goldlight.Mvvm.Base.Test
{
    /// <summary>
    /// Summary description for FileManagementTests
    /// </summary>
    [TestClass]
    public class FileManagementTests
    {
        private string _fileName = @"c:\file.txt";
        private string _altFileName = @"c:\file2.txt";
        private string _directory = @"c:\TestDirectory";

        #region Boilerplate
        public FileManagementTests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        [TestInitialize]
        public void Initialize()
        {
            if (File.Exists(_fileName))
            {
                File.Delete(_fileName);
            }

            if (File.Exists(_altFileName))
            {
                File.Delete(_altFileName);
            }

            if (Directory.Exists(_directory))
            {
                Directory.Delete(_directory, true);
            }
        }
        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion
        #endregion

        [TestMethod]
        public void RollbackDirectoryCreate()
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                KTMUtility.TxCreateDirectory(_directory);
            }
            Assert.IsFalse(Directory.Exists(_directory));
        }

        [TestMethod]
        public void SuccessfulDirectoryCreate()
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                KTMUtility.TxCreateDirectory(_directory);
                scope.Complete();
            }
            Assert.IsTrue(Directory.Exists(_directory));
        }

        [TestMethod]
        public void CopyFileRollback()
        {
            FileCreateSuccessful();
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                FileInfo f = new FileInfo(_fileName);
                f.TxCopy(_altFileName, null);
            }
            Assert.IsFalse(File.Exists(_altFileName));
        }

        [TestMethod]
        public void CopyFileComplete()
        {
            FileCreateSuccessful();
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                FileInfo f = new FileInfo(_fileName);
                f.TxCopy(_altFileName, null);
                scope.Complete();
            }
            Assert.IsTrue(File.Exists(_altFileName));
        }

        [TestMethod]
        public void MoveFileRollback()
        {
            FileCreateSuccessful();
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                FileInfo f = new FileInfo(_fileName);
                f.TxMove(_altFileName, null);
            }
            Assert.IsFalse(File.Exists(_altFileName));
        }

        [TestMethod]
        public void MoveFileComplete()
        {
            FileCreateSuccessful();
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                FileInfo f = new FileInfo(_fileName);
                f.TxMove(_altFileName, null);
                scope.Complete();
            }
            Assert.IsTrue(File.Exists(_altFileName));
        }

        [TestMethod]
        public void RollbackFileCreate()
        {
            //
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                using (SafeFileHandle handle = KTMUtility.TxCreateFile(_fileName, FileAccess.Write, FileShare.ReadWrite, FileMode.Create))
                {
                    using (FileStream fs = new FileStream(handle, FileAccess.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(fs))
                        {
                            sw.Write("Hello");
                        }
                    }
                }
            }
            Assert.IsFalse(File.Exists(_fileName));
        }

        [TestMethod]
        public void FileCreateSuccessful()
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                using (SafeFileHandle handle = KTMUtility.TxCreateFile(_fileName, FileAccess.Write, FileShare.ReadWrite, FileMode.Create))
                {
                    using (FileStream fs = new FileStream(handle, FileAccess.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(fs))
                        {
                            sw.Write("Hello");
                        }
                    }
                }
                scope.Complete();
            }
            Assert.IsTrue(File.Exists(_fileName));
        }

        [TestMethod]
        public void DeleteRolledback()
        {
            // Write the file out.
            FileCreateSuccessful();
            FileInfo f = new FileInfo(_fileName);
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                f.TxDelete();
            }
            Assert.IsTrue(File.Exists(_fileName));
        }

        [TestMethod]
        public void DeleteCommitted()
        {
            // Write the file out.
            FileCreateSuccessful();
            FileInfo f = new FileInfo(_fileName);
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew))
            {
                f.TxDelete();
                scope.Complete();
            }
            Assert.IsFalse(File.Exists(_fileName));
        }
    }
}
